/////////////////////////////////////////////     File     //////////////////////////////////////////////////
// Author: James Chen
// Filename: CUtilities.cpp
// Created: Friday, January 29, 2010 12:13:05 PM
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include ".\CUtilities.h"

//#define	CRITICAL_SECTION_RND		// Not strictly necessary, so off for speed

////////////////////// Singleton Implementation Begins //////////////////////
RNGen *RNGen::m_pInstance = 0;

RNGen::RNGen(void)
{
	srand((unsigned)time(NULL));

	this->SEED = rand();

	MZ = rand();
	MW = rand();

	RN = 0;
}

RNGen::~RNGen(void)
{
}

RNGen *RNGen::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new RNGen;
	}

	return m_pInstance;
}

void RNGen::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}

void RNGen::Reseed(void)
{
	this->SEED = rand();

	MZ = rand();
	MW = rand();
}

bool RNGen::LoadLastSeed(void)
{
	ifstream fin;

	fin.open("../data/seeds.txt");
	if(fin.fail())
	{
		return false;
	}

	fin >> this->MW;
	fin >> this->MZ;

	fin.close();

	return true;
}

bool RNGen::SaveSeed(void)
{
	ofstream fout;

	fout.open("../data/seeds.txt");
	if(fout.fail())
	{
		return false;
	}

	fout << this->MW << " " << this->MZ;

	fout.close();

	return true;
}

unsigned int RNGen::FastMW(void)
{
#ifdef		CRITICAL_SECTION_RND
	EnterCriticalSection(&rnd_CS);
#endif

	static int rnd_a = 12345678;
	static int rnd_b = 12393455;
	static int rnd_c = 45432838;

	rnd_a = rnd_a ^ 0x10010100;
	rnd_a = (rnd_a << 1) | ((rnd_a>> 31)&1);
	rnd_a ^= rnd_b ^ rnd_c;
	rnd_b = rnd_b * 255 + 32769;
	rnd_c = rnd_a + rnd_b + rnd_c + 1;

	this->RN = rnd_a;

#ifdef		CRITICAL_SECTION_RND
	LeaveCriticalSection(&rnd_CS);
#endif

	return RN;
}

unsigned int RNGen::FastW(void)
{
#ifdef		CRITICAL_SECTION_RND
	EnterCriticalSection(&rnd_CS);
#endif

	static int m_w = 12393455;    /* must not be zero */
	static int m_z = 45432838;    /* must not be zero */

    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);

	this->RN = (m_z << 16) + m_w;

#ifdef		CRITICAL_SECTION_RND
	LeaveCriticalSection(&rnd_CS);
#endif

    return RN;  /* 32-bit result */
}

unsigned int RNGen::FastI(void)
{
	RN = (214013*RN+2531011);
	RN = (RN>>16)&0x7FFF;

    return RN;  /* 32-bit result */
}

unsigned int RNGen::FastSeed(void)
{
	this->MZ = 36969 * (this->MZ & 65535) + (this->MZ >> 16);
    this->MW = 18000 * (this->MW & 65535) + (this->MW >> 16);

	this->RN = (this->MZ << 16) + this->MW;

	return RN;
}

unsigned int RNGen::Slow(void)
{
	RN = rand();
		
	return RN;
}

double RNGen::RandD(RNDTYPE TYPE, double LowValue, double HighValue)
{
	if(LowValue > HighValue)
	{
		double temp;

		temp = HighValue;
		HighValue = LowValue;
		LowValue = temp;
	}

	switch(TYPE)
	{
		case FASTMW:
			{
				this->Ratio = static_cast<double>(this->FastMW())/static_cast<double>(RANDMAX_FASTMW);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case FASTW:
			{
				this->Ratio = static_cast<double>(this->FastW())/static_cast<double>(RANDMAX_FASTW);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case FASTI:
			{
				this->Ratio = static_cast<double>(this->FastI())/static_cast<double>(RANDMAX_FASTI);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case FASTSEED:
			{
				this->Ratio = static_cast<double>(this->FastSeed())/static_cast<double>(RANDMAX_FASTSEED);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case SLOW:
			{
				this->Ratio = static_cast<double>(this->Slow())/static_cast<double>(RANDMAX_SLOW);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		default:
			{
				return 0.0;
			}
	}
}

float RNGen::RandF(RNDTYPE TYPE, float LowValue, float HighValue)
{
	if(LowValue > HighValue)
	{
		float temp;

		temp = HighValue;
		HighValue = LowValue;
		LowValue = temp;
	}

	switch(TYPE)
	{
		case FASTMW:
			{
				this->Ratio = static_cast<double>(this->FastMW())/static_cast<double>(RANDMAX_FASTMW);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case FASTW:
			{
				this->Ratio = static_cast<double>(this->FastW())/static_cast<double>(RANDMAX_FASTW);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case FASTI:
			{
				this->Ratio = static_cast<double>(this->FastI())/static_cast<double>(RANDMAX_FASTI);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case FASTSEED:
			{
				this->Ratio = static_cast<double>(this->FastSeed())/static_cast<double>(RANDMAX_FASTSEED);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case SLOW:
			{
				this->Ratio = static_cast<double>(this->Slow())/static_cast<double>(RANDMAX_SLOW);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		default:
			{
				return 0.0f;
			}
	}
}

double RNGen::RandBiasD(RNDTYPE TYPE, double LowValue, double HighValue, double *Bias)
{
	this->BiasSize = sizeof(&Bias);

	if(LowValue > HighValue)
	{
		float temp;

		temp = HighValue;
		HighValue = LowValue;
		LowValue = temp;
	}

	this->BiasDistance = (HighValue - LowValue) / this->BiasSize;

	

	return this->ReturnValueF;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

CTimer::CTimer(void)
{
	m_nFPS = 0;
    m_dTimeStart = 0.0;
    m_dTimeDelta = 0.0;

	m_dRunTime = 0.0;

	m_bPaused = false;
}

CTimer::~CTimer(void)
{
}

void CTimer::Initialize(void)
{
	LARGE_INTEGER liTicks;

    /* Get processor frequency */
    QueryPerformanceFrequency(&m_liTickFrequency);

    /* Get current tick count */
    QueryPerformanceCounter(&liTicks);

    /* Set the start time */
    m_dTimeStart = double(liTicks.QuadPart) / double(m_liTickFrequency.QuadPart);

    /* Reset the frames per second */
    m_nFPS = 0;
}

void CTimer::Update(void)
{
    static double sfTimePrev = GetTimeSinceStart();
    static double sfTimeLastUpdate = GetTimeSinceStart();
    static int snUpdates = 0;
    double fTimeNow = GetTimeSinceStart();

    /* Increment the frame counter */
    snUpdates++;

    /* Keep track of the frames per second */
    if((fTimeNow - sfTimePrev) > TIMERPOLLRATE)
    {
        m_nFPS = int(double(snUpdates) / (fTimeNow - sfTimePrev));
        snUpdates = 0;
        sfTimePrev = fTimeNow;
    }

    /* Calculate the change in time */
	if(!this->m_bPaused)
	{
		m_dTimeDelta = (fTimeNow - sfTimeLastUpdate);
		sfTimeLastUpdate = fTimeNow;
	}

	else
	{
		m_dTimeDelta = 0;
		sfTimeLastUpdate = fTimeNow;
	}

	this->m_dRunTime += m_dTimeDelta;
}

double CTimer::GetTimeSinceStart(void)
{
    LARGE_INTEGER liTicks;
    double fTime;

    /* Get the current tick count */
    QueryPerformanceCounter(&liTicks);

    /* get the current time since the beginning of the computer age */
    fTime = double(liTicks.QuadPart) / double(m_liTickFrequency.QuadPart);

    /* Calculate the time since the last reset */
    return (fTime - m_dTimeStart);
}

double CTimer::GetAverageWorkTime(void)
{
	this->m_dAccumulation = 0;

	for(ITERATOR = this->m_vProfiler.begin(); ITERATOR < this->m_vProfiler.end(); ITERATOR++)
	{
		this->m_dAccumulation += *ITERATOR;
	}

	this->m_dAccumulation /= this->m_vProfiler.size();

	return this->m_dAccumulation;
}

bool CTimer::GetAverageWorkTimeByCount(unsigned int Count, double &average)
{
	if(this->m_vProfiler.size() >= Count)
	{
		this->m_dAccumulation = 0;

		for(ITERATOR = this->m_vProfiler.begin(); ITERATOR < this->m_vProfiler.end(); ITERATOR++)
		{
			this->m_dAccumulation += *ITERATOR;
		}

		this->m_dAccumulation /= this->m_vProfiler.size();

		average = this->m_dAccumulation;

		return true;
	}

	else
	{
		return false;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


CMath *CMath::m_pInstance = 0;

CMath::CMath(void)
{
}

CMath::~CMath(void)
{
}

CMath *CMath::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CMath;
	}

	return m_pInstance;
}

void CMath::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}

float CMath::LinearInterpolationF(const float &Min, const float &Max, const float &Progression)
{
	return ((Max-Min)*Progression)+Min;
}
double CMath::LinearInterpolationD(const double &Min, const double &Max, const double &Progression)
{
	return ((Max-Min)*Progression)+Min;
}

D3DXVECTOR3 CMath::Slerp3D(const D3DXVECTOR3 &start, const D3DXVECTOR3 &end, const float &Progression)
{
	this->m_fTheta = acos(D3DXVec3Dot(&start, &end));

	return ((sin((1-Progression)*this->m_fTheta)/sin(this->m_fTheta))*start)+((sin(this->m_fTheta*Progression)/sin(this->m_fTheta))*end);
}

D3DXVECTOR2 CMath::Slerp2D(const D3DXVECTOR2 &start, const D3DXVECTOR2 &end, const float &Progression)
{
	this->m_fTheta = acos(D3DXVec2Dot(&start, &end));

	return ((sin((1-Progression)*this->m_fTheta)/sin(this->m_fTheta))*start)+((sin(this->m_fTheta*Progression)/sin(this->m_fTheta))*end);
}

double CMath::DistanceFast(const D3DXVECTOR3 &start, const D3DXVECTOR3 &end)
{
	return (end.x-start.x)*(end.x-start.x)+(end.y-start.y)*(end.y-start.y)+(end.z-start.z)*(end.z-start.z);
}

double CMath::DistanceTrue(const D3DXVECTOR3 &start, const D3DXVECTOR3 &end)
{
	return sqrt((end.x-start.x)*(end.x-start.x)+(end.y-start.y)*(end.y-start.y)+(end.z-start.z)*(end.z-start.z));
}

double CMath::DistanceFast(const double &xDiff, const double &yDiff, const double &zDiff)
{
	return (xDiff*xDiff)+(yDiff*yDiff)+(zDiff*zDiff);
}

double CMath::DistanceTrue(const double &xDiff, const double &yDiff, const double &zDiff)
{
	return sqrt((xDiff*xDiff)+(yDiff*yDiff)+(zDiff*zDiff));
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


CSystemAnalysis *CSystemAnalysis::m_pInstance = 0;

CSystemAnalysis::CSystemAnalysis(void)
{
	m_canReadCpu = false;
}

CSystemAnalysis::~CSystemAnalysis(void)
{
	Shutdown();
}

CSystemAnalysis *CSystemAnalysis::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CSystemAnalysis;
	}

	return m_pInstance;
}

void CSystemAnalysis::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}

void CSystemAnalysis::Initialize(void)
{
	// Initialize the flag indicating whether this object can read the system cpu usage or not.
	this->m_canReadCpu = true;

	// Create a query object to poll cpu usage.
	if(PdhOpenQuery(NULL, 0, &m_queryHandle) != ERROR_SUCCESS)
	{
		this->m_canReadCpu = false;
	}

	// Set query object to poll all cpus in the system.
	if(PdhAddCounter(m_queryHandle, TEXT("\\Processor(_Total)\\% processor time"), 0, &m_counterHandle) != ERROR_SUCCESS)
	{
		this->m_canReadCpu = false;
	}

	this->m_ulLastSampleTime = GetTickCount(); 

	this->m_cpuUsage = 0;

	this->memstat.dwLength = sizeof (this->memstat);
}


void CSystemAnalysis::Shutdown(void)
{
	if(m_canReadCpu)
	{
		PdhCloseQuery(this->m_queryHandle);
	}
}


void CSystemAnalysis::Update(void)
{ 
	if(m_canReadCpu)
	{
		if(GetTickCount() > (m_ulLastSampleTime + POLLRATE))
		{
			this->m_ulLastSampleTime = GetTickCount(); 

			PdhCollectQueryData(this->m_queryHandle);
        
			PdhGetFormattedCounterValue(this->m_counterHandle, PDH_FMT_LONG, NULL, &this->m_value);

			this->m_cpuUsage = this->m_value.longValue;
		}
	}

	GlobalMemoryStatusEx(&this->memstat);
}


int CSystemAnalysis::GetCpuUsage(void)
{
	return this->m_canReadCpu ? int(this->m_cpuUsage) : 0;
}

double CSystemAnalysis::GetMemUsage(void)
{
	return double(this->memstat.dwMemoryLoad);
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


CPathing::CPathing(void)
{
	this->m_dSpeed = 0;
	this->m_dTravelDistance = 0;
	this->m_dTotalDistance = 0;

	this->m_bContinuous = false;

	this->m_bLinked = false;
}

CPathing::~CPathing(void)
{
}

void CPathing::RemoveWaypoint(const int &ArrayPosition)
{
	if(static_cast<unsigned int>(ArrayPosition) > this->m_vPath.size())
	{
		return;
	}

	this->m_Iterator = this->m_vPath.begin();

	this->m_Iterator += ArrayPosition;

	this->m_vPath.erase(this->m_Iterator);
}
	
void CPathing::Update(const float &DeltaTime)
{
	this->m_dRemainingSpeed = this->m_dSpeed * DeltaTime;

	//CMath::GetInstance()->DistanceTrue(D3DXVECTOR3(0.0,0.0,0.0), D3DXVECTOR3(1.0,1.0,1.0));

	switch(this->m_nPathType)
	{
	case LINEAR:
		{
			for(this->m_Iterator = m_PositionIterator; this->m_Iterator < (this->m_vPath.end()-1); this->m_Iterator++)
			{
				
			}
		}

	default:
		{

		}
	}
}

void CPathing::AddWaypoints(const D3DXVECTOR3 *Waypoints, const int Count)
{
	static int i=0;

	for(i = 0; i < Count; i++)
	{
		this->m_vPath.push_back(Waypoints[i]);
	}

	if(this->m_vPath.size() == 1)
	{
		this->m_PositionIterator = this->m_vPath.begin();
	}
}

void CPathing::RotateYAxis(const float &angle)
{
	
}

double CPathing::CalculateDistance(void)
{
	static vector<D3DXVECTOR3>::iterator Iterator2;

	this->m_dTotalDistance = 0;

	for(this->m_Iterator = this->m_vPath.begin(); this->m_Iterator < (this->m_vPath.end()-1); this->m_Iterator++)
	{
		Iterator2 = this->m_Iterator+1;
		this->m_dTotalDistance += CMath::GetInstance()->DistanceTrue(Iterator2->x - this->m_Iterator->x,Iterator2->y - this->m_Iterator->y,Iterator2->z - this->m_Iterator->z);
	}

	return this->m_dTotalDistance;
}

void CPathing::Reset(void)
{
	this->m_PositionIterator = this->m_vPath.begin();

	this->m_VecPosition = *this->m_PositionIterator;

	this->m_dTravelDistance = 0;
	this->m_dTotalDistance = 0;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


CConversion *CConversion::m_pInstance = 0;

CConversion::CConversion(void)
{
}

CConversion::~CConversion(void)
{
}

CConversion *CConversion::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CConversion;
	}

	return m_pInstance;
}

void CConversion::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}

/* Linear Conversions [5/15/2010 1:10 PM by: James Chen] */

double CConversion::FeetToMeter(double value, bool inverse)
{
	return inverse ? value * MetrToFt : value * FtToMetr;
}

double CConversion::YardToMeter(double value, bool inverse)
{
	return inverse ? value * MetrToYard : value * YardToMetr;
}

double CConversion::YardToMile(double value, bool inverse)
{
	return inverse ? value * MiToYard : value * YardToMi;
}

double CConversion::MeterToMile(double value, bool inverse)
{
	return inverse ? value * MiToMetr : value * MetrToMi;
}

double CConversion::KilometerToMile(double value, bool inverse)
{
	return inverse ? value * MiToKM : value * KMToMi;
}

double CConversion::CentimeterToInch(double value, bool inverse)
{
	return inverse ? value * InchToCM : value * CMToInch;
}

/* Weight Conversions [5/15/2010 1:10 PM by: James Chen] */

double CConversion::PoundToKilogram(double value, bool inverse)
{
	return inverse ? value * KgToLb : value * LbToKg;
}

double CConversion::GramToPound(double value, bool inverse)
{
	return inverse ? value * LbToGram : value * GramToLb;
}

double CConversion::GrainToGram(double value, bool inverse)
{
	return inverse ? value * GramToGrn : value * GrnToGram;
}

double CConversion::PoundToGrain(double value, bool inverse)
{
	return inverse ? value * GrnToLb : value * LbToGrn;
}

double CConversion::GrainToKilogram(double value, bool inverse)
{
	return inverse ? value * KgToGrain : value * GrainToKg;
}

/* Speed Conversions [5/15/2010 1:10 PM by: James Chen] */

double CConversion::FeetPerSecToMach(double value, bool inverse)
{
	return inverse ? value * MachToFeetPerSecond : value * FeetPerSecondToMach;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


CRunManager *CRunManager::m_pInstance = 0;

CRunManager::CRunManager(void)
{
	this->m_bCounted = false;

	this->m_cpFileLocation = 0;
}

CRunManager::~CRunManager(void)
{
}

CRunManager *CRunManager::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CRunManager;
	}

	return m_pInstance;
}

void CRunManager::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}

void CRunManager::CountRun()
{
	if(this->m_bCounted)
		return;

	else
	{
		//Load the last counter value
		if(this->m_cpFileLocation)
		{
			this->fin.open(this->m_cpFileLocation);
		}

		else
		{
			this->fin.open("../data/RunCounter.txt");
		}

		if(this->fin.fail())
		{
			return;
		}

		this->fin >> this->m_uiCount;

		this->fin.close();

		//Save the current counter value
		if(this->m_cpFileLocation)
		{
			this->fout.open(this->m_cpFileLocation);
		}

		else
		{
			this->fout.open("../data/RunCounter.txt");
		}

		if(this->fout.fail())
		{
			return;
		}

		m_uiCount++;

		this->fout << this->m_uiCount;

		this->fout.close();
		
		this->m_bCounted = !this->m_bCounted;

		return;
	}
}

unsigned int CRunManager::GetCount(void)
{
	if(this->m_bCounted)
	{
		return this->m_uiCount;
	}

	else
	{
		this->CountRun();
		
		return this->m_uiCount;
	}
}

void CRunManager::Initialize(char *FileLocation)
{
	if(FileLocation)
	{
		this->m_cpFileLocation = FileLocation;
		
		return;
	}

	else
	{
		this->m_cpFileLocation = 0;
	
		return;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

//	Disable "signed/unsigned mismatch" warning.
#pragma warning (disable : 4018)

////////////////////// Singleton Implementation Begins //////////////////////
CDXInput *CDXInput::m_pInstance = 0;

CDXInput::CDXInput(void)
{
	m_lpDIObject		= NULL;
	m_lpDIKey			= NULL;
	m_lpDIMouse			= NULL;
	m_bExclusive		= false;
	m_dwKeyElements		= 0;
	m_dwMouseElements	= 0;
	memset(&m_didodMouse, 0, sizeof(m_didodMouse));
	memset(&m_didodKey, 0, sizeof(m_didodKey));
}

CDXInput::~CDXInput(void)
{
}

CDXInput *CDXInput::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CDXInput;
	}

	return m_pInstance;
}

void CDXInput::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}
/////////////////////// Singleton Implementation Ends ///////////////////////

bool CDXInput::InitDevices(HWND hWnd, HINSTANCE hMainInstance, bool bExclusive)
{
	//	Make sure DirectInput hasn't already been initialized.
	//if (m_lpDIObject)	DIERRBOX("DirectInput has already been initialized");

	m_hWnd		 = hWnd;			//	Store Main Window Handle.
	m_hInstance  = hMainInstance;	//	Store the main application instance.
	m_bExclusive = bExclusive;		//	Store whether or not we want exclusive access of the device.

	if (!InitKeyboard(hWnd, hMainInstance, bExclusive))
	{
		DIERRBOX("Failed to Initialize the Keyboard");
	}

	if (!InitMouse(hWnd, hMainInstance, bExclusive))
	{
		DIERRBOX("Failed to Initialize the Mouse");
	}

	//	Return success.
	return true;
}


bool CDXInput::InitKeyboard(HWND hWnd, HINSTANCE hMainInstance, bool bExclusive)
{
	//	Make sure Keyboard hasn't already been initialized.
	//if (m_lpDIKey)	DIERRBOX("DirectInput Keyboard has already been initialized");

	m_hWnd		 = hWnd;			//	Store Main Window Handle.
	m_hInstance  = hMainInstance;	//	Store the main application instance.
	m_bExclusive = bExclusive;		//	Store whether or not we want exclusive access of the device.

	//	Only create the Main DirectInput object if it hasn't been created yet.
	if (!m_lpDIObject)
	{
		//	Initialize the Direct Input COM object.
		if (FAILED(DirectInput8Create(hMainInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&m_lpDIObject, NULL)))
		{
			DIERRBOX("Failed to Create Main DirectInput Object");
		}
	}

	//	Create the Keyboard Device.
	if (FAILED(m_lpDIObject->CreateDevice(GUID_SysKeyboard, &m_lpDIKey, NULL)))
	{
		DIERRBOX("No Keyboard Found.");
	}

	//	Set the Cooperative level for the keyboard.
	if (m_bExclusive)
	{
		if (FAILED(m_lpDIKey->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE)))
		{
			DIERRBOX("Failed to SetCooperativeLevel of Keyboard for Exclusive Mode.");
		}
	}
	else
	{
		if (FAILED(m_lpDIKey->SetCooperativeLevel(hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
		{
			DIERRBOX("Failed to SetCooperativeLevel of Keyboard.");
		}
	}

	//	Set the Data Format for the keyboard.
	if (FAILED(m_lpDIKey->SetDataFormat(&c_dfDIKeyboard)))
	{
		DIERRBOX("Failed to SetDataFormat for the Keyboard.");
	}

	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	memset(&dipdw, 0, sizeof(dipdw));
	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = BUFFER_SIZE;	//	Arbitrary buffer size

	if (FAILED(m_lpDIKey->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
	{
		DIERRBOX("Could not Set the Properties for Buffered Input for Keyboard.");
	}

	//	Acquire the Keyboard.
	if (FAILED(m_lpDIKey->Acquire()))
	{
		DIERRBOX("Failed to Acquire Keyboard.");
	}

	//	Gets the Keyboard Layout.
	m_keyLayout = GetKeyboardLayout(0);

	//	Return success.
	return true;
}


bool CDXInput::InitMouse(HWND hWnd, HINSTANCE hMainInstance, bool bExclusive)
{
	//	Make sure the Mouse hasn't already been initialized.
	if (m_lpDIMouse)
	{
		DIERRBOX("DirectInput Mouse has already been Initialized.");
	}

	m_hWnd		 = hWnd;			//	Store Main Window Handle.
	m_hInstance  = hMainInstance;	//	Store the main application instance.
	m_bExclusive = bExclusive;		//	Store whether or not we want exclusive access of the device.

	//	Only create the Main DirectInput object if it hasn't been created yet.
	if (!m_lpDIObject)
	{
		//	Initialize the Direct Input COM object.
		if (FAILED(DirectInput8Create(hMainInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&m_lpDIObject, NULL)))
		{
			DIERRBOX("Failed to Create the DirectInput Object.");
		}
	}

	//	Create the Mouse Device.
	if (FAILED(m_lpDIObject->CreateDevice(GUID_SysMouse, &m_lpDIMouse, NULL)))
	{
		DIERRBOX("Mouse not Found.");
	}

	//	Set the Cooperative Level for the Mouse.
	if (m_bExclusive)
	{
		if (FAILED(m_lpDIMouse->SetCooperativeLevel(hWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE)))
		{
			DIERRBOX("Failed to SetCooperativeLevel for the Mouse in Exclusive Mode.");
		}
	}
	else
	{
		if (FAILED(m_lpDIMouse->SetCooperativeLevel(hWnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE)))
		{
			DIERRBOX("Failed to SetCooperativeLevel for the Mouse.");
		}
	}

	//	Set the Data format for the mouse.
	if (FAILED(m_lpDIMouse->SetDataFormat(&c_dfDIMouse2)))
	{
		DIERRBOX("Failed to SetDataFormat for the Mouse.");
	}

	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	memset(&dipdw, 0, sizeof(dipdw));
	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = BUFFER_SIZE;	//	Arbitrary buffer size

	if (FAILED(m_lpDIMouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
	{
		DIERRBOX("Could not Set the Properties for Buffered Input for Mouse.");
	}

	//	Acquire the mouse.
	if (FAILED(m_lpDIMouse->Acquire()))
	{
		DIERRBOX("Failed to Acquire the Mouse.");
	}

	//	Return success.
	return true;
}

void CDXInput::ShutdownDirectInput(void)
{
	//	Release the Mouse.
	if (m_lpDIMouse)
	{
		m_lpDIMouse->Unacquire();
		SAFE_RELEASE(m_lpDIMouse);
	}

	//	Release the Keyboard
	if (m_lpDIKey)
	{
		m_lpDIKey->Unacquire();
		SAFE_RELEASE(m_lpDIKey);
	}

	//	Release the Direct Input Device.
	if (m_lpDIObject)
	{
		SAFE_RELEASE(m_lpDIObject);
	}
}

bool CDXInput::ReadDevices(void)
{
	if (!ReadKeyboard())
		return false;

	if (!ReadBufferedKeyboard())
		return false;

	if (!ReadMouse())
		return false;

	if (!ReadBufferedMouse())
		return false;

	return true;
}


bool CDXInput::ReadKeyboard(void)
{
	HRESULT result;	//	For Error Tracking.

	//	Make sure the keyboard device was made.
	if (!m_lpDIKey)		return false;

	memset(&m_ucKeyState, 0, sizeof(m_ucKeyState));

	m_lpDIKey->Acquire();

	//	Keep attempting to acquire the Keyboard.
	if (result = m_lpDIKey->GetDeviceState(sizeof(m_ucKeyState), (LPVOID)m_ucKeyState) == DIERR_INPUTLOST)	   
	{
		//	Try to re-acquire the device.
		if (FAILED(result = m_lpDIKey->Acquire()))
		{
			//	Could not re-acquire the Keyboard.
			return false;
		}
	}

	//	Return success.
	return true;
}

bool CDXInput::ReadBufferedKeyboard(void)
{
	HRESULT result;	//	For Error Tracking.

	//	Make sure the keyboard device was made.
	if (!m_lpDIKey)		return false;

	m_lpDIKey->Acquire();

	m_dwKeyElements = BUFFER_SIZE;
	memset(&m_didodKey, 0, sizeof(m_didodKey));
	//	Keep attempting to acquire the Keyboard.
	if (result = m_lpDIKey->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didodKey, &m_dwKeyElements, 0) == DIERR_INPUTLOST)
	{
		//	Could not re-acquire the Keyboard.
		if (FAILED(result = m_lpDIKey->Acquire()))
			return false;
	}

	//	Return success.
	return true;
}


bool CDXInput::GetKey(UCHAR ucKey)
{
	//	Check to see if the key was pressed.
	if (m_ucKeyState[ucKey] & 0x80)
		return true;

	//	The Key was not Pressed.
	return false;
}

//	Disable the "not all control paths return a value" warning.
#pragma warning (disable : 4715)


char CDXInput::CheckKeys(void)
{	
	//	Get the Current Keyboard State.
	if (!(GetKeyboardState(m_ucAsciiVals)))
	{
		DIERRBOX("Could not GetKeyboardState.");
	}

	unsigned short num = 0;
	UINT vkcode = 0;

	//	Go through each keyboard state.
	for (int i = 0; i < 256; i++)
	{
		if (m_ucKeyState[i] & 0x80)
		{
			//	Map the Scan Code from Direct Input to a Virtual Key value....
			vkcode = MapVirtualKeyEx(i, 1, m_keyLayout);
			//	...and tranlsate that Virtual Key into an Ascii Value.
			ToAsciiEx(vkcode, i, m_ucAsciiVals, &num, 0, m_keyLayout);
		}
	}

	//	Return the Ascii Value.
	return (char)num;
}

char CDXInput::CheckBufferedKeys(void)
{
	//	Get the Current Keyboard State.
	if (!(GetKeyboardState(m_ucAsciiVals)))
	{
		DIERRBOX("Could not GetKeyboardState.");
	}

	unsigned short num = 0;
	UINT vkcode = 0;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwKeyElements; i++)
	{
		for (unsigned int j = 0; j < 256; j++)
		{
			if ((m_didodKey[i].dwOfs == j) && (m_didodKey[i].dwData & 0x80))
			{
				vkcode = MapVirtualKeyEx(m_didodKey[i].dwOfs, 1, m_keyLayout);
				ToAsciiEx(vkcode, m_didodKey[i].dwOfs, m_ucAsciiVals, &num, 0, m_keyLayout);
			}
		}
	}

	//	Return the Ascii Value.
	return (char)num;	
}

//	Enable the "not all control paths return a value" warning.
#pragma warning (default : 4715)


bool CDXInput::GetBufferedKey(UCHAR ucKey)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwKeyElements; i++)
	{
		//	If the Key is pressed return success.
		if ((m_didodKey[i].dwOfs == ucKey) && (m_didodKey[i].dwData & 0x80))
			return true;
	}

	//	Return Failure.
	return false;
}


bool CDXInput::GetBufferedKeyEx(UCHAR ucKey)
{
	if (GetKey(ucKey))
	{
		if (!m_bKeysPressed[ucKey])
		{
			m_bKeysPressed[ucKey] = true;
			return true;
		}
	}
	else if (!GetKey(ucKey))
		m_bKeysPressed[ucKey] = false;

	//	The Key was not pressed.
	return false;
}


bool CDXInput::ReadMouse(void)
{
	HRESULT result;	//	For Error Tracking.

	//	Make sure the Mouse Device was made.
	if (!m_lpDIMouse)	return false;

	if (FAILED(m_lpDIMouse->Poll()))
		m_lpDIMouse->Acquire();

	memset(&m_diMouseState, 0, sizeof(m_diMouseState));
	//	Keep attempting to acquire the Mouse.
	if (result = m_lpDIMouse->GetDeviceState(sizeof(m_diMouseState), &m_diMouseState) == DIERR_INPUTLOST)
	{
		//	Try to re-acquire the device.
		if (FAILED(result = m_lpDIMouse->Acquire()))
			//	Serious error - Could not re-acquire the Mouse.
			return false;
	}

	//	Return success.
	return true;
}


bool CDXInput::ReadBufferedMouse(void)
{
	HRESULT result;	//	For Error Tracking.

	//	Make sure the Mouse Device was made.
	if (!m_lpDIMouse)	return false;

	if (FAILED(m_lpDIMouse->Poll()))
		m_lpDIMouse->Acquire();

	m_dwMouseElements = BUFFER_SIZE;
	memset(&m_didodMouse, 0, sizeof(m_didodMouse));
	//	Keep attempting to acquire the Mouse.
	if (result = m_lpDIMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didodMouse, &m_dwMouseElements, 0) == DIERR_INPUTLOST)
	{
		//	Could not re-acquire the Mouse.
		if (FAILED(result = m_lpDIMouse->Acquire()))
			return false;
	}

	if (m_dwMouseElements > 0)
		return true;

	//	Return success.
	return true;
}

bool CDXInput::OnMouseButtonRelease(BYTE mButton)
{
	//	Check to see if the button was pressed and set a flag.
	if (GetMouseButton(mButton))
	{
		if (!m_bMouseButtons[mButton])
			m_bMouseButtons[mButton] = true;
	}
	//	Checks to see if the button isn't pressed and if the flag is true then
	//	go ahead and change the flag and return true.
	else if (!GetMouseButton(mButton))
	{
		if (m_bMouseButtons[mButton])
		{
			m_bMouseButtons[mButton] = false;
			//	The Mouse Button was release.
			return true;
		}
	}

	//	Mouse button was not released.
	return false;
}

bool CDXInput::GetMouseButton(BYTE mButton)
{
	//	Check to see if the Mouse Button was pressed.
	if (m_diMouseState.rgbButtons[mButton] & 0x80)
		return true;

	//	Button Not Pressed.
	return false;
}


bool CDXInput::GetBufferedMouseButton(BYTE mButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwMouseElements; i++)
	{
		//	If the Key is pressed return success.  Add 12 because DirectInput uses 
		//	DIMOFS_BUTTON0 and so forth for the check on this.
		if ((m_didodMouse[i].dwOfs == (DWORD)(mButton + 12)) && (m_didodMouse[i].dwData & 0x80))
			return true;
	}

	//	Return Failure.
	return false;
}


LONG CDXInput::GetMouseAxis(LONG lAxis)
{
	//	Check the Axis and return its state.
	switch (lAxis)
	{
	case XAXIS:
		return m_diMouseState.lX;
		break;

	case YAXIS:
		return m_diMouseState.lY;
		break;

	case ZAXIS:
		return m_diMouseState.lZ;
		break;
	};

	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

CSound::CSound(float volume)
{
	this->channel = 0;
	this->sound = 0;

	this->volume = volume;
}

CSound::~CSound(void)
{
}

FMOD::Sound **CSound::GetSound()
{
	return &this->sound;
}

FMOD::Channel **CSound::GetChannel()
{
	return &this->channel;
}

void CSound::SetVolume(float volume)
{
	this->volume = volume;
}

float CSound::GetVolume()
{
	return this->volume;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


////////////////////// Singleton Implementation Begins //////////////////////
CSoundManager *CSoundManager::m_pInstance = 0;

CSoundManager::CSoundManager(void)
{
	this->counter = -1;
	this->pitch = -1.0f;
}

CSoundManager::~CSoundManager(void)
{
}

CSoundManager *CSoundManager::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CSoundManager;
	}

	return m_pInstance;
}

void CSoundManager::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}
/////////////////////// Singleton Implementation Ends ///////////////////////

void CSoundManager::Init()
{
	result = FMOD::System_Create(&system);		// Create the main system object.
	if (result != FMOD_OK)
	{
		exit(-1);
	}

	result = system->init(100, FMOD_INIT_NORMAL, 0);	// Initialize FMOD.
	if (result != FMOD_OK)
	{
		exit(-1);
	}
}

void CSoundManager::Update()
{
	this->system->update();
}


void CSoundManager::CleanUp()
{
	CSound *temp;
	for(unsigned int i = 0; i < this->sounds.size(); i++)
	{
		temp = this->sounds[i];
		delete temp;
		temp = 0;
	}

	this->sounds.clear();

	this->system->release();
}

int CSoundManager::AddSound(const char *name, FMOD_MODE Type)
{
	CSound* temp = new CSound;

	this->result = system->createSound(name, Type, 0, temp->GetSound());

	this->sounds.push_back(temp);

	return ++counter;
	
}

void CSoundManager::PlaySound(unsigned int id)
{
	if(id < this->sounds.size())
	{
		system->playSound(FMOD_CHANNEL_REUSE, *this->sounds[id]->GetSound(), false, this->sounds[id]->GetChannel());
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////